package top.gokzzz.common.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * Java Bean 工具類
 *
 * @author Gok
 * @version 1.3
 */
public class BeanUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 用於緩存 BeanCopier
     * 使用 WeakHashMap 防止內容泄漏（JVM 內存緊張時自動回收）
     */
    private static final Map<String, BeanCopier> BEAN_COPIER_MAP = Collections.synchronizedMap(new WeakHashMap<>());

    static {
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 關閉未知字段檢查
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 關閉空對象不讓序列化檢查
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);// 關閉默認時間戳記轉化格式
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); // 自定義轉化時間格式

        OBJECT_MAPPER.registerModule(new JavaTimeModule());
    }

    /**
     * Java 對象 -> Json 字符串
     *
     * @param obj Java 對象
     * @return Json 字符串
     */
    public static String bean2Json(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Object to JSON conversion failed", e);
        }
    }

    /**
     * Json 字符串 -> Java 對象
     *
     * @param jsonStr Json 字符串
     * @param clazz   目標類型
     * @return Java 對象
     */
    public static <T> T json2Bean(String jsonStr, Class<T> clazz) {
        if (jsonStr == null || jsonStr.isEmpty()) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(jsonStr, clazz);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON to Object conversion failed", e);
        }
    }

    /**
     * Json 字符串 -> Java 數組
     *
     * @param jsonStr Json 字符串
     * @param clazz   目標類型
     * @return Java 數組
     */
    public static <T> T[] json2Array(String jsonStr, Class<T[]> clazz) {
        if (jsonStr == null || jsonStr.isEmpty()) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(jsonStr, clazz);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON to Array conversion failed", e);
        }
    }


    /**
     * Java Bean -> Map<String, Object>
     * 使用 cglib
     *
     * @param object Java Bean
     * @return {@link Map }<{@link String }, {@link Object }>
     */
    public static Map<String, Object> bean2Map(Object object) {
        Map<String, Object> map = new HashMap<>();
        if (object != null) {
            BeanMap beanMap = BeanMap.create(object);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * Map<String, Object> -> Java Bean
     * 使用 cglib
     *
     * @param map       map
     * @param beanClass Java Bean 類
     * @return {@link T }
     * @throws Exception 異常
     */
    public static <T> T map2Bean(Map<String, Object> map, Class<T> beanClass) throws Exception {
        T bean = beanClass.newInstance();
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 使用 cglib 的 BeanCopier 實現拷貝
     * <p/>
     * 缺陷：<br/>
     * 1、類型匹配嚴格，需要自己實現轉換器<br/>
     * 2、淺拷貝<br/>
     * 3、首次創建 BeanCopier 時生成字節碼，耗時明顯<br/>
     * 4、無 getter 的欄位無法被拷貝
     *
     * @param source 源对象
     * @param target 目标类
     */
    private static void copy(Object source, Object target) {
        String key = source.getClass().getName() + "_" + target.getClass().getName();
        BeanCopier beanCopier;

        if (!BEAN_COPIER_MAP.containsKey(key)) {
            //參數 1：源對象類
            //參數 2：目標對象類
            //參數 3：是否使用自定義轉換器
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_MAP.put(key, beanCopier);
        } else {
            beanCopier = BEAN_COPIER_MAP.get(key);
        }
        beanCopier.copy(source, target, null);
    }

    /**
     * 使用 cglib 的 BeanCopier 實現拷貝，支持忽略指定字段
     * <p>
     * 缺陷：<br/>
     * 1、需手动处理忽略字段的逻辑，性能略低于原生 BeanCopier<br/>
     * 2、浅拷贝<br/>
     */
    public static void copyWithIgnore(Object source, Object target, String... ignoreFields) {
        // 1. 使用原生 BeanCopier 进行全量拷贝
        copy(source, target);

        // 2. 通过反射清除目标对象中需忽略的字段值
        if (ignoreFields != null && ignoreFields.length > 0) {
            BeanMap targetMap = BeanMap.create(target);
            for (String field : ignoreFields) {
                if (targetMap.containsKey(field)) {
                    targetMap.put(field, null); // 设为 null 或保持原值（根据需求调整）
                }
            }
        }
    }

    /**
     * 深度拷貝，需要 implements Serializable（性能垃圾，慎用）
     *
     * @param obj Java Bean 對象
     * @return {@link T }
     */
    @SuppressWarnings("unchecked")
    public static <T> T deepCopy(T obj) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (T) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
